﻿/*! ************************************************************
 * \file
 * \brief 提供一些数据处理的辅助工具函数
 *
 * \authors 林胜勇
 *
 * \date
 * \verbatim
 * 变更记录：
 * 2023-11-30，林胜勇:
 *   创建文件
 * \endverbatim
 ****************************************************************/

#pragma once

#include "chinese.h"

#include <algorithm>
#include <cmath>
#include <functional>
#include <inttypes.h>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <string.h>
#include <string>
#include <type_traits>
#include <vector>

// 以下定义区分操作系统的宏
#if _WIN32 || WIN32 || __WIN32__
#define CPPC_OS_WINDOWS
#elif defined(__APPLE__) || defined(MACOSX) || defined(macintosh) || defined(Macintosh)
#define CPPC_OS_APPLE
#elif defined(__linux__) || defined(__LINUX__) || defined(__linux)
#define CPPC_OS_LINUX
#ifdef __ANDROID__
#define CPPC_OS_ANDROID
#endif
#endif

#if __WORDSIZE == 64 || defined(_WIN64)
#define CPPC_OS_X64
#else
#define CPPC_OS_X32
#endif

#ifdef CPP_OS_WINDOWS
#include <Windows.h>
#else
#define sprintf_s snprintf
#endif

typedef uint8_t uchar, byte, BYTE, uint8;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint16_t uint16, ushort;
typedef uint32_t uint32, uint;
typedef uint64_t uint64;
typedef unsigned long ulong; // 一般用来配合size_t和size_type来使用，表示不同平台下的最长数据索引
typedef unsigned long long ulonglong, ullong;
typedef long long longlong, llong;

#define FLOAT_EPSINON float(1e-5f)    ///< float型数据的精度，按有效位数为7位
#define DOUBLE_EPSINON double(1e-13f) ///< double型数据的精度，按有效位数为15位

#define FACTOR_KB_TO_BYTE uint64(1024ll)
#define FACTOR_MB_TO_BYTE uint64(1024ll * 1024ll)
#define FACTOR_GB_TO_BYTE uint64(1024ll * 1024ll * 1024ll)
#define FACTOR_TB_TO_BYTE uint64(1024ll * 1024ll * 1024ll * 1024ll)

// 声明变量为不使用的变量 避免编译时出现警告
#define UNUSED_PARAM(pramName) (void)(pramName)

#define DEFINE_TO_STRING(x) DEFINE_TO_STRING_(x)
#define DEFINE_TO_STRING_(x) #x

// 宏函数重载支持-开始
#define __NARG__(...) __NARG_I_(__VA_ARGS__, __RSEQ_N())
#define __NARG_I_(...) __ARG_N(__VA_ARGS__)
#define __ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, \
                _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42,  \
                _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62,  \
                _63, N, ...)                                                                                         \
    N
#define __RSEQ_N()                                                                                                      \
    63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, \
        34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, \
        5, 4, 3, 2, 1, 0

// general definition for any function name
#define _VFUNC_(name, n) name##n
#define _VFUNC(name, n) _VFUNC_(name, n)
#define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__))(__VA_ARGS__)

/**!
 格式化技巧：printf格式化64位整数可用系统宏：PRId64、PRIu64
#include <inttypes.h>
uint64_t value = 1560;
printf("value = %" PRId64 "\n", value);
*/

#pragma pack(1)
// 面定义32位数值与16位数值型的联合，用于提取内存字节顺序，具体大小端由使用的程序决定
// 即这里的i8[4]和i8[2]可能保存的是大端，也可能是小端
typedef union {
    char i8[4]; // 保存转内存字节
    int value;
} DataUnionInt32;

typedef union {
    char i8[4]; // 保存转内存字节
    unsigned int value;
} DataUnionUInt32;

typedef union {
    char i8[4]; // 保存转内存字节
    float value;
} DataUnionFloat32;

typedef union {
    char i8[2];
    short value;
} DataUnionShort16;

typedef union {
    char i8[2];
    unsigned short value;
} DataUnionUShort16;

#pragma pack()

namespace cppc {
// 检查对象是否是指针，配合宏使用，开始
template <typename T>
inline bool isPtr(T *v) {
    return true;
}

extern bool isPtr(...);

template <typename T>
inline T &anyToObj(T *v) {
    return *v;
}
template <typename T>
inline T &anyToObj(T &v) {
    return v;
}
template <typename T>
inline T &anyToObj(std::shared_ptr<T> &v) {
    return *(v.get());
}

// 检查对象是否是指针，配合宏使用，结束

/// 单例类实现体
#define INSTANCE_IMPL(class_name, ...)                                              \
    class_name &class_name::Instance() {                                            \
        static std::shared_ptr<class_name> s_instance(new class_name(__VA_ARGS__)); \
        static class_name &s_instance_ref = *s_instance;                            \
        return s_instance_ref;                                                      \
    }

/// 安全释放指针对应空间
template <typename T>
inline void safeDelete(T *&target) {
    if ((nullptr != target) && (NULL != target)) {
        delete target;
        target = nullptr;
    }
}

/// 安全释放指针对应空间
template <typename T>
inline void safeDeleteVoidPtr(void *&target) {
    if ((nullptr != target) && (NULL != target)) {
        T *temp = static_cast<T *>(target);
        delete temp;
        temp = nullptr;
        target = nullptr;
    }
}

/// 浮点数与0比较
/// \return 1：大于0,0：等于0,-1：小于0
template <typename T>
inline int compareZero(T value, T error = FLOAT_EPSINON) {
    error = abs(error);
    if (value < -error) {
        return -1;
    } else if (value > error) {
        return 1;
    }
    return 0;
}

/// 检查vector是否包含某个值，返回包含的个数
template <typename T>
inline int contain(const std::vector<T> &vectorObj, const T &tar) {
    return std::count(vectorObj.begin(), vectorObj.end(), tar);
}

/// 是否在某个范围之内
template <class T>
inline bool isInRange(T x, T lower, T upper, bool checkEqual = true) {
    if (checkEqual) {
        return (x >= lower && x <= upper);
    } else {
        return (x > lower && x < upper);
    }
}

/// 获取环境变量内容，以'$'开头
extern std::string getEnv(const std::string &key);

/// 将日期时间字符串按指定格式解析成tm
/// \param timeStr 时间字符串，如2023-11-29T12:30:45
/// \param fmt 格式，常见的占位符包括 %Y（年份）、%m（月份）、%d（日期）、%H（小时）、%M（分钟）
/// \return
extern tm parseTime(const std::string &timeStr, const std::string &fmt);

/// 获取程序编译时间
inline struct tm getCompileTime() {
    struct tm date = parseTime(__DATE__, "%b %d %Y");
    struct tm time = parseTime(__TIME__, "%H:%M:%S");
    date.tm_hour = time.tm_hour;
    date.tm_min = time.tm_min;
    date.tm_sec = time.tm_sec;

    return date;
}

/// 获取程序编译时间的可视化格式，如2020-06-27T12:34:56
inline std::string getCompileTimeStr() {
    struct tm appTime = getCompileTime();
    char retVal[128] = "";
    sprintf_s(retVal, 128, "%d-%02d-%02dT%02d:%02d:%02d", appTime.tm_year + 1900, appTime.tm_mon + 1, appTime.tm_mday,
              appTime.tm_hour, appTime.tm_min, appTime.tm_sec);
    return std::string(retVal);
}

} // namespace cppc

namespace cppc {

template <int>
struct placeholder {};
} // namespace cppc

namespace std {
template <int N>
struct is_placeholder<cppc::placeholder<N>>
    : integral_constant<int, N + 1> {
};
} // namespace std

namespace cppc {
template <std::size_t... Ns>
struct index_sequence {
};

template <std::size_t N, std::size_t... Ns>
struct make_index_sequence
    : make_index_sequence<N - 1, N - 1, Ns...> {
};

template <std::size_t... Ns>
struct make_index_sequence<0, Ns...>
    : index_sequence<Ns...> {
};

template <typename T>
inline bool safeReserve(std::vector<T> &vectorObj, uint size) {
    try {
        vectorObj.reserve(size);
        return true;
    } catch (...) {
        return false;
    }
}

template <typename T>
inline bool safeResize(std::vector<T> &vectorObj, uint size) {
    try {
        vectorObj.resize(size);
        return true;
    } catch (...) {
        return false;
    }
}

/// 浮点数保留指定小数位
/// \param value 浮点值
/// \param decimalNum 小数位个数
/// \param round 是否四舍五入
template <typename T>
T setPrecision(T value, uint decimalNum, bool round = false) {
    if (round) {
        return std::round(value * std::pow(10, decimalNum)) / std::pow(10, decimalNum);
    } else {
        return std::floor(value * std::pow(10, decimalNum)) / std::pow(10, decimalNum);
    }
}

} // namespace cppc
